/*
 * EditDownloadDialog.java
 *
 * Copyright 2007, 2008 Tiberiumlabs
 *
 * This file is part of Tiberiumlabs Lailaps.
 *
 * Tiberiumlabs Lailaps is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * Tiberiumlabs Lailaps is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.tiberiumlabs.lailaps.gui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.util.ResourceBundle;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.validator.UrlValidator;
import org.tiberiumlabs.lailaps.Mediator;
import org.tiberiumlabs.lailaps.actions.ActionFactory;
import org.tiberiumlabs.lailaps.gui.elements.ExceptionDialog;
import org.tiberiumlabs.lailaps.gui.elements.OpenButton;
import org.tiberiumlabs.lailaps.list.DownloadItem;
import org.tiberiumlabs.lailaps.resources.ImageLoader;
import org.tiberiumlabs.lailaps.settings.ApplicationSettings;
import org.tiberiumlabs.lailaps.settings.Settings;
import org.tiberiumlabs.swing.DesktopToolkit;

/**
 *
 * @author <a href="mailto:paranoid.tiberiumlabs@gmail.com">Paranoid</a>
 */
public class EditDownloadDialog {

    // <editor-fold defaultstate="collapsed" desc=" keys for i18n ">
    private static final String DIALOG_TITLE = "dialog.title";
    private static final String URL_TITLE = "url.title";
    private static final String URL_TOOLTIP = "url.tooltip";
    private static final String FILE_TITLE = "file.title";
    private static final String FILE_TOOLTIP = "file.tooltip";
    private static final String OPTIONS_TITLE = "options.title";
    private static final String OPTIONS_AUTOSTART = "options.autostart";
    private static final String OPTIONS_AUTOSTART_TOOLTIP = "options.autostart.tooltip";
    private static final String BUTTON_OK_NAME = "button.ok.name";
    private static final String BUTTON_OK_SHORT = "button.ok.short";
    private static final String BUTTON_OK_LONG = "button.ok.long";
    private static final String BUTTON_CANCEL_NAME = "button.cancel.name";
    private static final String BUTTON_CANCEL_SHORT = "button.cancel.short";
    private static final String BUTTON_CANCEL_LONG = "button.cancel.long";
    private static final String BUTTON_BROWSE_NAME = "button.browse.name";
    private static final String BUTTON_BROWSE_SHORT = "button.browse.short";
    private static final String BUTTON_BROWSE_LONG = "button.browse.long";
    private static final String CHOOSER_TITLE = "chooser.title";
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" static objects ">
    private static final GUIBuilder guiBuilder = Mediator.getMediator().getGuiBuilder();
    private static final ResourceBundle bundle = ResourceBundle.getBundle("org/tiberiumlabs/lailaps/resources/messages/edit");
    private static final Border EMPTY_BORDER = GUIFactory.createEmptyBorder();
    private static final Log LOG = LogFactory.getLog(EditDownloadDialog.class);
    // </editor-fold>

    // <editor-fold defaultstate="collapsed" desc=" private data objects ">
    private DownloadItem item;
    private int row = -1;

    private JTextField urlField = null;
    private JTextField fileField = null;
    private JCheckBox autoStart = null;
    private JDialog dialog = null;
    // </editor-fold>


    /** Creates a new instance of EditDownloadDialog */
    public EditDownloadDialog() {
        //Scaning clipboard for valid url (only on add)
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        Transferable contents = clipboard.getContents(null);
        boolean hasTransferableText = (contents != null) &&
                contents.isDataFlavorSupported(DataFlavor.stringFlavor);
        if (hasTransferableText) {
            try {
                String content = (String) clipboard.getData(DataFlavor.stringFlavor);
                if (validator.isValid(content)) {
                    item = new DownloadItem(content);
                }
            } catch (Exception ex) {
                LOG.warn("Exception while accesing system clipboard", ex);
            }
        }
        if (item == null) {
            item = new DownloadItem();
        }
        createAndShowGui();
    }
    public EditDownloadDialog(String url) {
        item = new DownloadItem(url);
        createAndShowGui();
    }
    public EditDownloadDialog(int row) {
        this.row = row;
        this.item = Mediator.getMediator().getDownloadsListModel().getItem(row);
        createAndShowGui();
    }

    private void createAndShowGui() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                construct();
                dialog.toFront();
                urlField.requestFocusInWindow();
                urlField.setSelectionStart(0);
                urlField.setSelectionEnd(Short.MAX_VALUE);
            }
        });
    }

    private void construct() {

        // <editor-fold defaultstate="collapsed" desc=" content pane with vertical layout ">
        JPanel content = GUIFactory.createVerticalBoxPanel();
        content.setBorder(EMPTY_BORDER);
        // </editor-fold>

        String url = item.getUrl();

        // <editor-fold defaultstate="collapsed" desc=" url input ">
        urlField = new JTextField();
        DesktopToolkit.setMaxComponentHeight(urlField);
        urlField.setToolTipText(bundle.getString(URL_TOOLTIP));
        urlField.setText(url);
        urlField.getDocument().addDocumentListener(new UrlListener());
        JPanel urlPanel = GUIFactory.createHorizontalBoxPanel();
        urlPanel.setBorder(GUIFactory.createTitledEmptyBorder(bundle.getString(URL_TITLE)));
        urlPanel.add(urlField);
        content.add(urlPanel);
        content.add(Box.createVerticalStrut(12));
        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc=" file input ">
        fileField = new JTextField();
        fileField.setToolTipText(bundle.getString(FILE_TOOLTIP));
        fileField.setText(item.getSafeOutputPath() + item.getOutputFile());
        JButton fileButton = new OpenButton(new BrowseAction());
        JPanel filePanel = GUIFactory.createHorizontalBoxPanel();
        filePanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createTitledBorder(bundle.getString(FILE_TITLE)),
                BorderFactory.createEmptyBorder(0, 6, 6, 6)));
        filePanel.add(fileField);
        filePanel.add(Box.createHorizontalStrut(6));
        filePanel.add(fileButton);
        filePanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, filePanel.getPreferredSize().height));
        content.add(filePanel);
        content.add(Box.createVerticalStrut(12));
        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc=" options input ">
        autoStart = new JCheckBox(bundle.getString(OPTIONS_AUTOSTART));
        autoStart.setToolTipText(bundle.getString(OPTIONS_AUTOSTART_TOOLTIP));
        autoStart.setEnabled(row == -1);
        autoStart.setSelected(Settings.getApplicationSettings().isAutostartDownloads());

        //JPanel optionsPanel = new JPanel(new GridLayout(2, 2)); // TODO when get more options - make it grid
        JPanel optionsPanel = GUIFactory.createHorizontalBoxPanel();
        optionsPanel.add(autoStart);
        optionsPanel.setBorder(GUIFactory.createTitledEmptyBorder(bundle.getString(OPTIONS_TITLE)));
        optionsPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, optionsPanel.getPreferredSize().height));
        content.add(optionsPanel);
        content.add(Box.createVerticalStrut(12));
        content.add(Box.createVerticalGlue());
        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc=" buttons ">
        JButton okButton = new JButton(new OkAction());
        JButton cancelButton = new JButton(new CancelAction());
        cancelButton.setMargin(new Insets(2, 5, 2, 5));
        okButton.setMaximumSize(cancelButton.getMaximumSize());
        okButton.setPreferredSize(cancelButton.getPreferredSize());
        JPanel buttonsPanel = GUIFactory.createHorizontalBoxPanel();
        buttonsPanel.add(Box.createHorizontalGlue());
        buttonsPanel.add(okButton);
        buttonsPanel.add(Box.createHorizontalStrut(6));
        buttonsPanel.add(cancelButton);
        buttonsPanel.setMaximumSize(new Dimension(Integer.MAX_VALUE, buttonsPanel.getPreferredSize().height));
        content.add(buttonsPanel);
        // </editor-fold>

        // <editor-fold defaultstate="collapsed" desc=" create and show dialog ">
        // TODO check if we need to use SwingUtilities here
        dialog = new JDialog(guiBuilder.isMainWindowVisible() ? guiBuilder.getMainWindow() : null, bundle.getString(DIALOG_TITLE), false);
        dialog.setContentPane(content);

        // TODO check if it really works
        KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
        dialog.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, cancelCommandName);
        dialog.getRootPane().getActionMap().put(cancelCommandName, cancelButton.getAction());

        dialog.pack();
        int width = dialog.getWidth();
        if (width > 400) {
            dialog.setSize(400, dialog.getHeight());
        } else {
            dialog.setSize(dialog.getWidth() + 20, dialog.getHeight());
        }
        dialog.setMinimumSize(dialog.getSize());
        dialog.getRootPane().setDefaultButton(okButton);
        dialog.setLocation(DesktopToolkit.getWindowLocation(dialog.getSize()));
        dialog.setVisible(true);
        // </editor-fold>

    }

    private static final String cancelCommandName = "CancelCommand:DisposeDialog";
    private class CancelAction extends AbstractAction {
        public CancelAction() {
            putValue(NAME, bundle.getString(BUTTON_CANCEL_NAME));
            putValue(SHORT_DESCRIPTION, bundle.getString(BUTTON_CANCEL_SHORT));
            putValue(LONG_DESCRIPTION, bundle.getString(BUTTON_CANCEL_LONG));
            putValue(LARGE_ICON_KEY, ImageLoader.getButtonCancelIcon());
        }
        
        @Override
        public void actionPerformed(ActionEvent e) {
            dialog.dispose();
        }
    }

    private class OkAction extends AbstractAction {
        public OkAction() {
            putValue(NAME, bundle.getString(BUTTON_OK_NAME));
            putValue(SHORT_DESCRIPTION, bundle.getString(BUTTON_OK_SHORT));
            putValue(LONG_DESCRIPTION, bundle.getString(BUTTON_OK_LONG));
            putValue(LARGE_ICON_KEY, ImageLoader.getButtonOkIcon());
        }
        
        @Override
        public void actionPerformed(ActionEvent e) {
            dialog.dispose();

            item.setUrl(urlField.getText());
            String fullPath = fileField.getText();
            int index = fullPath.lastIndexOf(ApplicationSettings.FILESEPARATOR);
            if (index >= 0) {
                String outputPath = fullPath.substring(0, index+1); 
                if (!Settings.getApplicationSettings().getOutputFolder().equals(outputPath)) {
                    item.setOutputPath(outputPath);
                }
            }
            item.setOutputFile(fullPath.substring(index+1));

            ActionFactory.silentAddElement(item, -1, autoStart.isSelected());
        }
    }

    private class BrowseAction extends AbstractAction {
        public BrowseAction() {
            putValue(NAME, bundle.getString(BUTTON_BROWSE_NAME));
            putValue(SHORT_DESCRIPTION, bundle.getString(BUTTON_BROWSE_SHORT));
            putValue(LONG_DESCRIPTION, bundle.getString(BUTTON_BROWSE_LONG));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            JFileChooser fileChooser = new JFileChooser(item.getSafeOutputPath());
            fileChooser.setDialogTitle(bundle.getString(CHOOSER_TITLE));
            fileChooser.setDialogType(JFileChooser.SAVE_DIALOG);
            // TODO may be to select folders to and add file name after folder name?
            fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
            fileChooser.setMultiSelectionEnabled(false);
            // TODO may be better to use Document?
            fileChooser.setSelectedFile(new File(fileField.getText())); // TODO check if file is not created by dialog at this moment

            int res = fileChooser.showSaveDialog(dialog);
            if (res == JFileChooser.APPROVE_OPTION) {
                File f = fileChooser.getSelectedFile();
                try {
                    fileField.setText(f.getCanonicalPath());
                } catch (IOException ex) {
                    new ExceptionDialog(ex);
                }
            }
        }
    }

    private static final Color yellow = new Color(255, 255, 220);
    private static final Color red = new Color(255, 235, 235);
    /* TODO
     * in future try to use Java native regex for url validation and parsing:
     * (https|ftp|http):\/\/([^\/]+)(.*)(\ |\s)
     * (https|ftp|http|www):\/\/([^\/]+)(.*)(\ |\s)
     */
    private static final UrlValidator validator = new UrlValidator();
    private class UrlListener implements DocumentListener {
        private String SEPARATOR = Settings.getApplicationSettings().FILESEPARATOR;

        @Override
        public void insertUpdate(DocumentEvent e) {
            fireUrlChanged();
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            fireUrlChanged();
        }

        @Override
        public void changedUpdate(DocumentEvent e) {
            fireUrlChanged();
        }

        public void fireUrlChanged() {

            String url = urlField.getText();
            String fileName = DownloadItem.getFilenameFromUrl(url);
            Document fileDocument = fileField.getDocument();
            try {
                int l = fileDocument.getLength();
                int i = fileDocument.getText(0, l).lastIndexOf(SEPARATOR);
                if (i >= 0) {
                    i++;
                    fileDocument.remove(i, l-i);
                    fileDocument.insertString(i, fileName, null);
                }
            } catch (BadLocationException badLocationException) {
                new ExceptionDialog(badLocationException);
            }

            if (validator.isValid(url)) {
                if (urlField.getBackground() != yellow) {
                    urlField.setBackground(yellow);
                }
            } else {
                if (urlField.getBackground() != red) {
                    urlField.setBackground(red);
                }
            }

        }
    }

}
